package de.geraldschenke.tictactoe.common.ai;

import android.util.Log;
import de.geraldschenke.tictactoe.common.GameEvent;
import de.geraldschenke.tictactoe.common.PlayerEvent;
import de.geraldschenke.tictactoe.common.RemotePlayer;
import de.geraldschenke.tictactoe.common.Stone;
import de.geraldschenke.tictactoe.server.GameThread;

public class NormalAI implements RemotePlayer {

	private GameThread gameThread;
	private int playerId = -1;

	public NormalAI(GameThread gameThread) {
		this.gameThread = gameThread;
	}

	@Override
	public void handleGameEvent(GameEvent gameEvent) {
		if (gameEvent.gameOver || gameEvent.currentPlayer != playerId) {
			Log.d("NormalAI", "got Event, but not my turn or Game Over");
			return;
		}

		int[][] points = new int[gameEvent.board.length][gameEvent.board[0].length];
		Stone[] line = new Stone[gameEvent.board.length];
		for(int row = 0; row < gameEvent.board.length; row++){
			for(int column = 0; column < gameEvent.board[row].length; column++){
				int fieldpoints = -1;
				if (gameEvent.board[row][column] == null){
					// check row
					line = getCompleteRow(row,gameEvent.board);
					fieldpoints = Math.max(fieldpoints, calculatePoints(line));
					// check column
					line = getCompleteColumn(column,gameEvent.board);
					fieldpoints = Math.max(fieldpoints, calculatePoints(line));
					// check diagonals
					if (row == column){
						line = getCompleteDiagonalFromTopLeftToBottomRigth(gameEvent.board);
						fieldpoints = Math.max(fieldpoints, calculatePoints(line));
					}
					if(row == (gameEvent.board.length-1)-column){
						line = getCompleteDiagonalFromTopRightToBottomLeft(gameEvent.board);
						fieldpoints = Math.max(fieldpoints, calculatePoints(line));
					}
				} // else set points to -1 beacause we cannot set a stone here
				points[row][column] = fieldpoints;
			}
		}
		
		int maxPoints = -1;
		int bestRow = 0;
		int bestColumn = 0;
		for(int i = 0; i < points.length; i++){
			for(int j = 0; j < points[i].length; j++){
				if (points[i][j] > maxPoints){
					maxPoints = points[i][j];
					bestRow = i;
					bestColumn = j;					
				}
			}
		}
		
		// set in middle if no good move is possible
		if (maxPoints <= 1 && gameEvent.board[gameEvent.board.length/2][gameEvent.board.length/2] == null){
			bestRow = gameEvent.board.length/2;
			bestColumn = gameEvent.board.length/2;
		}
		
		PlayerEvent playerEvent = new PlayerEvent();
		playerEvent.type = PlayerEvent.Type.SET;
		playerEvent.x = bestRow;
		playerEvent.y = bestColumn;
		gameThread.handlePlayerEvent(playerEvent);
	}

	private Stone[] getCompleteDiagonalFromTopRightToBottomLeft(Stone[][] board) {
		Stone[] result = new Stone[board.length];
		for (int i = 0; i < board.length; i++) {
			result[i] = board[i][(board.length-1)-i];
		}
		return result;
	}

	private Stone[] getCompleteDiagonalFromTopLeftToBottomRigth(Stone[][] board) {
		Stone[] result = new Stone[board.length];
		for (int i = 0; i < board.length; i++) {
			result[i] = board[i][i];
		}
		return result;
	}

	private Stone[] getCompleteRow(int row, Stone[][] board) {
		return board[row];
	}


	private Stone[] getCompleteColumn(int column, Stone[][] board) {
		Stone[] result = new Stone[board.length];
		for (int i = 0; i < board.length; i++) {
			result[i] = board[i][column];
		}
		return result;
	}

	private int calculatePoints(Stone[] line) {
		int count_myStones = 0;
		int count_enemyStones = 0;
		
		for (int i = 0; i < line.length; i++) {
			if (isMyStone(line[i])){
				count_myStones++;
			}else if (line[i] != null){
				count_enemyStones++;
			}
		}
		
		if (count_myStones == line.length-1){
			// we can end this game and win!
			return Integer.MAX_VALUE;
		}
		
		if (count_enemyStones == line.length-1){
			// we must prevent other player from winning!
			return Integer.MAX_VALUE-1;
		}
		
		if (count_enemyStones == 0){
			// we have a chance in this row
			if (count_myStones > 0){
				return count_myStones+1;
			}else{
				return 1;
			}
		}
		return 0;
	}

	private boolean isMyStone(Stone stone) {
		// TODO this is only true if we're player2
		return Stone.O == stone;
	}

	@Override
	public void setPlayerId(int id) {
		playerId = id;
	}

}
